﻿using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using System.Collections.Generic;
using Xunit;
using Xunit.Abstractions;
namespace Odyssey.Consul.xUnit
{
    using Http;
    public class xUnitAgent
    {
        ITestOutputHelper outputHelper;

        public xUnitAgent(ITestOutputHelper output)
        {
            outputHelper = output;
        }

        private ConsulDispatch BuildConsul()
        {
            var serviceCollection = new ServiceCollection();
            serviceCollection.AddLogging();
            serviceCollection.AddOdysseyHttp((httpConfiguration) =>
            {
                httpConfiguration.JsonSerializerSettingsBuilder = () =>
                {
                    return new JsonSerializerSettings()
                    {
                        NullValueHandling = NullValueHandling.Ignore,
                        DefaultValueHandling = DefaultValueHandling.Ignore,
                    };
                };
                httpConfiguration.HttpResponseFilter = async (httpResponseMessage) =>
                {
                    if (httpResponseMessage.StatusCode != System.Net.HttpStatusCode.OK)
                    {
                        var errorContent = await httpResponseMessage.Content.ReadAsStringAsync();
                        outputHelper.WriteLine(errorContent);
                        httpResponseMessage.EnsureSuccessStatusCode();
                    }
                };
            }).AddConsulCore((consulConfiguration) =>
            {
                consulConfiguration.EnableAcl = true;
                consulConfiguration.Host = "http://localhost:8500";
                consulConfiguration.AccessorID = "9d4786d8-a073-0778-b45d-d4fc3197b19c";
                consulConfiguration.SecretID = "d163859b-8363-4e37-7acf-913be2fd66b5";

                //consulConfiguration.AccessorID = "9d4786d8-a073-0778-b45d-d4fc3197b19c";
                //consulConfiguration.SecretID = "2e08b156-f3f3-c072-adab-896833d44625";
            });

            return serviceCollection.BuildServiceProvider().GetRequiredService<ConsulDispatch>();
        }

        [Fact]
        public void AgentTest()
        {
            var consul = BuildConsul();
            var members = consul.Agent.ListMembers().Result;
            outputHelper.WriteLine("members action:");
            foreach (var item in members)
            {
                outputHelper.WriteLine(JsonConvert.SerializeObject(item));
            }
            Assert.Equal("DESKTOP-0TM90AB", members[0].Name);

            outputHelper.WriteLine("self config action:");
            var configurations = consul.Agent.Self().Result; outputHelper.WriteLine(JsonConvert.SerializeObject(configurations.Config));
            Assert.True(configurations.Config.Datacenter == "dc1");

            outputHelper.WriteLine("reload:");
            consul.Agent.Reload().Wait();

            outputHelper.WriteLine("maintenance:");
            consul.Agent.EnableMaintenanceMode(new Models.ArguEnableMaintenanceMode()
            {
                Enable = true,
                Reason = "test"
            });

            consul.Agent.EnableMaintenanceMode(new Models.ArguEnableMaintenanceMode()
            {
                Enable = false,
                Reason = "test"
            });

            outputHelper.WriteLine("Metric:");
            outputHelper.WriteLine(consul.Agent.Metrics().Result);

        }

        [Fact]
        public void AgentCheckTest()
        {
            var consul = BuildConsul();

            outputHelper.WriteLine("check action:");
            var checks = consul.Agent.CheckList().Result;
            foreach (var item in checks)
            {
                outputHelper.WriteLine(JsonConvert.SerializeObject(item));
            }
            outputHelper.WriteLine("check register action:");
            var headers = new Dictionary<string, string[]>() {
                {"iTPS-TOKEN",new string[]{ "123456" } }
            };
            consul.Agent.CheckRegister(new Models.ArguCheckRegister()
            {
                ID = "Check_Payment_Gateway",
                Name = "Check_Payment_Gateway",
                Notes = "测试支付网关",
                DeregisterCriticalServiceAfter = "10m",
                HTTP = "http://localhost:5103/nereus/show",
                Method = "GET",
                Header = headers,
                Interval = "5s",

            }).Wait();

            consul.Agent.CheckRegister(new Models.ArguCheckRegister()
            {
                ID = "Check_Payment_Gateway_Faild",
                Name = "Check_Payment_Gateway_Faild",
                Notes = "测试支付网关模拟失败",
                DeregisterCriticalServiceAfter = "10m",
                HTTP = "http://localhost:5103/nereus/show",
                Method = "POST",
                Header = headers,
                Interval = "5s",

            }).Wait();

            consul.Agent.CheckRegister(new Models.ArguCheckRegister()
            {
                ID = "Check_Payment_Gateway_TTL",
                Name = "Check_Payment_Gateway_TTL",
                Notes = "测试支付网关模拟失败",
                TTL = "10s",
            }).Wait();


            checks = consul.Agent.CheckList().Result;
            Assert.True(checks.Count > 0);
            Assert.True(checks[0].Name.IndexOf("Check_Payment_Gateway") > -1);

            foreach (var item in checks)
            {
                outputHelper.WriteLine(JsonConvert.SerializeObject(item));
            }
            var checkId = "Check_Payment_Gateway_Faild";
            consul.Agent.CheckDeregister(checkId).Wait();

            checks = consul.Agent.CheckList().Result;
            foreach (var item in checks)
            {
                if (item.CheckID.Equals(checkId))
                {
                    throw new System.Exception($"deregister {checkId} faild!");
                }
            }
            outputHelper.WriteLine("check TTL action:");
            checkId = "Check_Payment_Gateway_TTL";
            var arguCheckTTL = new Models.ArguCheckTTL()
            {
                ID = checkId,
                Note = "ttl test",
            };
            consul.Agent.CheckTTLFail(arguCheckTTL).Wait();
            consul.Agent.CheckTTLPass(arguCheckTTL).Wait();
            consul.Agent.CheckTTLWarn(arguCheckTTL).Wait();
            consul.Agent.CheckTTLUpdate(new Models.ArguCheckTTLUpdate()
            {
                ID = checkId,
                Output = "ttl update test",
                Status = Features.EnumServiceStatus.Passing.ToString().ToLower(),
            }).Wait();

        }

        [Fact]
        public void AgentServiceTest()
        {
            var consul = BuildConsul();
            outputHelper.WriteLine("service register action:");
            consul.Agent.ServiceRegister(new Models.ArguServiceRegister()
            {
                ID = "pay_gateway",
                Name = "pay_gateway",
                Tags = new List<string>() { "primary", "v1" },
                Address = "127.0.0.1",
                Port = 5103,
                Meta = new Dictionary<string, string>() { { "pay-gateway", "1.0" } },
                EnableTagOverride = false,
                Check = new Models.Internal.CheckRegister()
                {
                    HTTP = "http://localhost:5103/nereus/show",
                    Interval = "10s",
                },
                Weights = new Models.Internal.Weights()
                {
                    Passing = 10,
                    Warning = 1
                }
            }).Wait();
            outputHelper.WriteLine("service list action:");
            var services = consul.Agent.ServiceList().Result;

            Assert.True(services.Count > 0);
            Assert.True(services[0].ID == "pay_gateway");

            foreach (var item in services)
            {
                outputHelper.WriteLine(JsonConvert.SerializeObject(item));
            }

            var serviceConfiguration = consul.Agent.ServiceConfiguration("pay_gateway").Result;
            Assert.True(serviceConfiguration.ID == "pay_gateway");
            outputHelper.WriteLine(JsonConvert.SerializeObject(serviceConfiguration));

            outputHelper.WriteLine("local service health action:");
            var healthInfoById = consul.Agent.ServiceHealth(id: "pay_gateway").Result;
            var healthInfoByName = consul.Agent.ServiceHealth(name: "pay_gateway").Result;

            consul.Agent.ServiceEnableMaintenance(new Models.ArguServiceEnableMaintenance()
            {
                Enable = true,
                Reason = "service enable maintenance",
                ServiceID = "pay_gateway"
            }).Wait();

            outputHelper.WriteLine("service deregister action:");
            consul.Agent.ServiceDeregister("pay_gateway").Wait();
            services = consul.Agent.ServiceList().Result;

            Assert.True(services.Count == 0);
        }
    }
}
